

package com.aaa.sso.config;

import com.aaa.sso.service.MyUserDetailService;
import com.aaa.utils.JWTUtil;
import com.aaa.vo.Result;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @program: qy172-springsecurity03
 * @description:
 * @author: 闫克起2
 * @create: 2024-02-21 11:00
 **/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDetailService userDetailService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //设置表单信息
        http.formLogin()
                .loginProcessingUrl("/sso/login")
                .successHandler(successHandler())
                .failureHandler(failureHandler()) //登录失败后执行的处理函数
                .permitAll();

        //权限不足
        http.exceptionHandling().accessDeniedHandler(deniedHandler());
//        //禁用跨域伪造请求
        http.csrf().disable();
        //运行跨域
//        http.cors();
        //其他所有的请求路径都需要认证后访问
        http.authorizeRequests().anyRequest().authenticated();
    }

    //权限不足
    private AccessDeniedHandler deniedHandler() {
        return new AccessDeniedHandler() {
            @Override
            public void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
                response.setContentType("application/json;charset=utf-8");
                //1. 生成json数据。
                Result result = new Result(4003, "权限不足,联系管理员", null);
                //转化为json字符串
                String jsonString = JSON.toJSONString(result);
                //输出给前端
                PrintWriter writer = response.getWriter();
                writer.print(jsonString);

                writer.flush();
                writer.close();
            }
        };
    }

    //登录失败的函数
    private AuthenticationFailureHandler failureHandler() {
        return new AuthenticationFailureHandler() {
            @Override
            public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
                response.setContentType("application/json;charset=utf-8");
                //1. 生成json数据。
                Result result = new Result(5000, "登录失败", null);
                //转化为json字符串
                String jsonString = JSON.toJSONString(result);
                //输出给前端
                PrintWriter writer = response.getWriter();
                writer.print(jsonString);

                writer.flush();
                writer.close();
            }
        };
    }

    @Autowired
    private StringRedisTemplate redisTemplate;

    private AuthenticationSuccessHandler successHandler() {
        return new AuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//                response.setCharacterEncoding("utf-8");
                response.setContentType("application/json;charset=utf-8");
                //获取登录成功的账户
                String name = authentication.getName();
                Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

                List<String> permission = authorities.stream().map(item -> item.getAuthority()).collect(Collectors.toList());
                //使用JWT生成token令牌
                String token = JWTUtil.createToken(name, permission);
                //把令牌保存到redis中---设置过期时----移除信息---1功能--写两天。
                redisTemplate.opsForValue().set(token,"",24, TimeUnit.HOURS);
                //1. 生成json数据。
                Result result = new Result(2000, "登录成功", token);
                //2.相应为json数据给前端
                PrintWriter writer = response.getWriter();
                //吧java对象转化为json字符串---fastjson工具
                String jsonString = JSON.toJSONString(result);
                writer.print(jsonString);

                writer.flush();
                writer.close();

            }
        };
        //jdk8新特点==周日4个。
    }
}

